Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.64% covered (success)
96.64%
1208 / 1250
56.52% covered (warning)
56.52%
13 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
PptCharts
96.64% covered (success)
96.64%
1208 / 1250
56.52% covered (warning)
56.52%
13 / 23
219
0.00% covered (danger)
0.00%
0 / 1
 render
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 writeChart
84.72% covered (warning)
84.72%
61 / 72
0.00% covered (danger)
0.00%
0 / 1
8.23
 writeSpreadsheet
93.75% covered (success)
93.75%
30 / 32
0.00% covered (danger)
0.00%
0 / 1
6.01
 writeElementWithValAttribute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeSingleValueOrReference
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
7
 writeTitle
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
4
 writePlotArea
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
12
 writeLegend
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
1 / 1
5
 writeLayout
76.92% covered (warning)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
5.31
 writeTypeArea
93.33% covered (success)
93.33%
42 / 45
0.00% covered (danger)
0.00%
0 / 1
9.02
 writeTypeBar
93.20% covered (success)
93.20%
96 / 103
0.00% covered (danger)
0.00%
0 / 1
17.09
 writeTypeBar3D
96.81% covered (success)
96.81%
91 / 94
0.00% covered (danger)
0.00%
0 / 1
15
 writeTypeDoughnut
95.40% covered (success)
95.40%
83 / 87
0.00% covered (danger)
0.00%
0 / 1
20
 writeTypePie
95.06% covered (success)
95.06%
77 / 81
0.00% covered (danger)
0.00%
0 / 1
15
 writeTypePie3D
100.00% covered (success)
100.00%
78 / 78
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeLine
100.00% covered (success)
100.00%
83 / 83
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeRadar
100.00% covered (success)
100.00%
81 / 81
100.00% covered (success)
100.00%
1 / 1
13
 writeTypeScatter
100.00% covered (success)
100.00%
87 / 87
100.00% covered (success)
100.00%
1 / 1
16
 writeChartRelationships
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 writeSeriesMarker
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 writeAxis
99.42% covered (success)
99.42%
171 / 172
0.00% covered (danger)
0.00%
0 / 1
26
 writeAxisGridlines
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4 * presentations documents.
5 *
6 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12 *
13 * @see        https://github.com/PHPOffice/PHPPresentation
14 *
15 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16 */
17
18declare(strict_types=1);
19
20namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
21
22use PhpOffice\Common\Adapter\Zip\ZipInterface;
23use PhpOffice\Common\Drawing as CommonDrawing;
24use PhpOffice\Common\XMLWriter;
25use PhpOffice\PhpPresentation\Exception\FileRemoveException;
26use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException;
27use PhpOffice\PhpPresentation\PhpPresentation;
28use PhpOffice\PhpPresentation\Shape\Chart;
29use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
30use PhpOffice\PhpPresentation\Shape\Chart\Legend;
31use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
32use PhpOffice\PhpPresentation\Shape\Chart\Title;
33use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
41use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
42use PhpOffice\PhpPresentation\Style\Border;
43use PhpOffice\PhpPresentation\Style\Fill;
44use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
45use PhpOffice\PhpSpreadsheet\IOFactory;
46use PhpOffice\PhpSpreadsheet\Spreadsheet;
47
48class PptCharts extends AbstractDecoratorWriter
49{
50    public function render(): ZipInterface
51    {
52        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
53            $shape = $this->getDrawingHashTable()->getByIndex($i);
54            if ($shape instanceof Chart) {
55                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
56
57                if ($shape->hasIncludedSpreadsheet()) {
58                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
59                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
60                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
61
62                    // remove temp file
63                    if (false === @unlink($pFilename)) {
64                        throw new FileRemoveException($pFilename);
65                    }
66                }
67            }
68        }
69
70        return $this->getZip();
71    }
72
73    /**
74     * Write chart to XML format.
75     *
76     * @return string XML Output
77     */
78    protected function writeChart(Chart $chart): string
79    {
80        // Create XML writer
81        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
82
83        // XML header
84        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
85
86        // c:chartSpace
87        $objWriter->startElement('c:chartSpace');
88        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
89        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
90        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
91
92        // c:date1904
93        $objWriter->startElement('c:date1904');
94        $objWriter->writeAttribute('val', '1');
95        $objWriter->endElement();
96
97        // c:lang
98        $objWriter->startElement('c:lang');
99        $objWriter->writeAttribute('val', 'en-US');
100        $objWriter->endElement();
101
102        // c:chart
103        $objWriter->startElement('c:chart');
104
105        // Title?
106        if ($chart->getTitle()->isVisible()) {
107            // Write title
108            $this->writeTitle($objWriter, $chart->getTitle());
109        }
110
111        // c:autoTitleDeleted
112        $objWriter->startElement('c:autoTitleDeleted');
113        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
114        $objWriter->endElement();
115
116        // c:view3D
117        $objWriter->startElement('c:view3D');
118
119        // c:rotX
120        $objWriter->startElement('c:rotX');
121        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
122        $objWriter->endElement();
123
124        // c:hPercent
125        $hPercent = $chart->getView3D()->getHeightPercent();
126        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
127
128        // c:rotY
129        $objWriter->startElement('c:rotY');
130        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
131        $objWriter->endElement();
132
133        // c:depthPercent
134        $objWriter->startElement('c:depthPercent');
135        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
136        $objWriter->endElement();
137
138        // c:rAngAx
139        $objWriter->startElement('c:rAngAx');
140        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
141        $objWriter->endElement();
142
143        // c:perspective
144        $objWriter->startElement('c:perspective');
145        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
146        $objWriter->endElement();
147
148        $objWriter->endElement();
149
150        // Write plot area
151        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
152
153        // Legend?
154        if ($chart->getLegend()->isVisible()) {
155            // Write legend
156            $this->writeLegend($objWriter, $chart->getLegend());
157        }
158
159        // c:plotVisOnly
160        $objWriter->startElement('c:plotVisOnly');
161        $objWriter->writeAttribute('val', '1');
162        $objWriter->endElement();
163
164        // c:dispBlanksAs
165        $objWriter->startElement('c:dispBlanksAs');
166        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
167        $objWriter->endElement();
168
169        $objWriter->endElement();
170
171        // c:spPr
172        $objWriter->startElement('c:spPr');
173
174        // Fill
175        $this->writeFill($objWriter, $chart->getFill());
176
177        // Border
178        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
179            $this->writeBorder($objWriter, $chart->getBorder(), '');
180        }
181
182        // Shadow
183        if ($chart->getShadow()->isVisible()) {
184            // a:effectLst
185            $objWriter->startElement('a:effectLst');
186
187            // a:outerShdw
188            $objWriter->startElement('a:outerShdw');
189            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
190            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
191            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
192            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
193            $objWriter->writeAttribute('rotWithShape', '0');
194
195            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
196
197            $objWriter->endElement();
198
199            $objWriter->endElement();
200        }
201
202        $objWriter->endElement();
203
204        // External data?
205        if ($chart->hasIncludedSpreadsheet()) {
206            // c:externalData
207            $objWriter->startElement('c:externalData');
208            $objWriter->writeAttribute('r:id', 'rId1');
209
210            // c:autoUpdate
211            $objWriter->startElement('c:autoUpdate');
212            $objWriter->writeAttribute('val', '0');
213            $objWriter->endElement();
214
215            $objWriter->endElement();
216        }
217
218        $objWriter->endElement();
219
220        // Return
221        return $objWriter->getData();
222    }
223
224    /**
225     * Write chart to XML format.
226     *
227     * @return string String output
228     */
229    protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
230    {
231        // Create new spreadsheet
232        $spreadsheet = new Spreadsheet();
233
234        // Set properties
235        $title = $chart->getTitle()->getText();
236        if (0 == strlen($title)) {
237            $title = 'Chart';
238        }
239        $spreadsheet->getProperties()
240            ->setCreator(
241                $presentation->getDocumentProperties()->getCreator()
242            )
243            ->setLastModifiedBy(
244                $presentation->getDocumentProperties()->getLastModifiedBy()
245            )
246            ->setTitle($title);
247
248        // Add chart data
249        $sheet = $spreadsheet->setActiveSheetIndex(0);
250        $sheet->setTitle('Sheet1');
251
252        // Write series
253        $seriesIndex = 0;
254        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
255            // Title
256            $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, 1, $series->getTitle());
257
258            // X-axis
259            $axisXData = array_keys($series->getValues());
260            $numAxisXData = count($axisXData);
261            for ($i = 0; $i < $numAxisXData; ++$i) {
262                $sheet->setCellValueByColumnAndRow(1, $i + 2, $axisXData[$i]);
263            }
264
265            // Y-axis
266            $axisYData = array_values($series->getValues());
267            $numAxisYData = count($axisYData);
268            for ($i = 0; $i < $numAxisYData; ++$i) {
269                $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, $i + 2, $axisYData[$i]);
270            }
271
272            ++$seriesIndex;
273        }
274
275        // Save to string
276        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
277        $writer->save($tempName);
278
279        // Load file in memory
280        $returnValue = file_get_contents($tempName);
281        if (false === @unlink($tempName)) {
282            throw new FileRemoveException($tempName);
283        }
284
285        return $returnValue;
286    }
287
288    /**
289     * Write element with value attribute.
290     *
291     * @param XMLWriter $objWriter XML Writer
292     */
293    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
294    {
295        $objWriter->startElement($elementName);
296        $objWriter->writeAttribute('val', $value);
297        $objWriter->endElement();
298    }
299
300    /**
301     * Write single value or reference.
302     *
303     * @param XMLWriter $objWriter XML Writer
304     */
305    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
306    {
307        if (!$isReference) {
308            // Value
309            $objWriter->writeElement('c:v', $value);
310
311            return;
312        }
313
314        // Reference and cache
315        // c:strRef
316        $objWriter->startElement('c:strRef');
317        // c:strRef/c:f
318        $objWriter->writeElement('c:f', $reference);
319        // c:strRef/c:strCache
320        $objWriter->startElement('c:strCache');
321        // c:strRef/c:strCache/c:ptCount
322        $objWriter->startElement('c:ptCount');
323        $objWriter->writeAttribute('val', '1');
324        $objWriter->endElement();
325
326        // c:strRef/c:strCache/c:pt
327        $objWriter->startElement('c:pt');
328        $objWriter->writeAttribute('idx', '0');
329        // c:strRef/c:strCache/c:pt/c:v
330        $objWriter->writeElement('c:v', $value);
331        // c:strRef/c:strCache/c:pt
332        $objWriter->endElement();
333        // c:strRef/c:strCache
334        $objWriter->endElement();
335        // c:strRef
336        $objWriter->endElement();
337    }
338
339    /**
340     * Write series value or reference.
341     *
342     * @param XMLWriter $objWriter XML Writer
343     * @param array<int, mixed> $values
344     */
345    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
346    {
347        // c:strLit / c:numLit
348        // c:strRef / c:numRef
349        $referenceType = ($isReference ? 'Ref' : 'Lit');
350
351        // Get data type from first non-null value
352        $dataType = array_reduce($values, function ($carry, $item) {
353            if (!isset($item)) {
354                return $carry;
355            }
356
357            return is_numeric($item) ? 'num' : 'str';
358        }, 'num');
359
360        $objWriter->startElement('c:' . $dataType . $referenceType);
361
362        $numValues = count($values);
363        if (!$isReference) {
364            // Value
365
366            // c:ptCount
367            $objWriter->startElement('c:ptCount');
368            $objWriter->writeAttribute('val', count($values));
369            $objWriter->endElement();
370
371            // Add points
372            for ($i = 0; $i < $numValues; ++$i) {
373                // c:pt
374                $objWriter->startElement('c:pt');
375                $objWriter->writeAttribute('idx', $i);
376                $objWriter->writeElement('c:v', (string) ($values[$i]));
377                $objWriter->endElement();
378            }
379        } else {
380            // Reference
381            $objWriter->writeElement('c:f', $reference);
382            $objWriter->startElement('c:' . $dataType . 'Cache');
383
384            // c:ptCount
385            $objWriter->startElement('c:ptCount');
386            $objWriter->writeAttribute('val', count($values));
387            $objWriter->endElement();
388
389            // Add points
390            for ($i = 0; $i < $numValues; ++$i) {
391                // c:pt
392                $objWriter->startElement('c:pt');
393                $objWriter->writeAttribute('idx', $i);
394                $objWriter->writeElement('c:v', (string) ($values[$i]));
395                $objWriter->endElement();
396            }
397
398            $objWriter->endElement();
399        }
400
401        $objWriter->endElement();
402    }
403
404    /**
405     * Write Title.
406     */
407    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
408    {
409        // c:title
410        $objWriter->startElement('c:title');
411
412        // c:tx
413        $objWriter->startElement('c:tx');
414
415        // c:rich
416        $objWriter->startElement('c:rich');
417
418        // a:bodyPr
419        $objWriter->writeElement('a:bodyPr', null);
420
421        // a:lstStyle
422        $objWriter->writeElement('a:lstStyle', null);
423
424        // a:p
425        $objWriter->startElement('a:p');
426
427        // a:pPr
428        $objWriter->startElement('a:pPr');
429        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
430        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
431        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
432        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
433        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
434        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
435
436        // a:defRPr
437        $objWriter->writeElement('a:defRPr', null);
438
439        $objWriter->endElement();
440
441        // a:r
442        $objWriter->startElement('a:r');
443
444        // a:rPr
445        $objWriter->startElement('a:rPr');
446        $objWriter->writeAttribute('lang', 'en-US');
447        $objWriter->writeAttribute('dirty', '0');
448        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
449        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
450        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
451        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
452        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
453        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
454        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
455        $objWriter->writeAttribute('cap', $subject->getFont()->getCapitalization());
456
457        // Font - a:solidFill
458        $objWriter->startElement('a:solidFill');
459
460        $this->writeColor($objWriter, $subject->getFont()->getColor());
461
462        $objWriter->endElement();
463
464        // Font - a:latin
465        $objWriter->startElement('a:latin');
466        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
467        $objWriter->endElement();
468
469        $objWriter->endElement();
470
471        // a:t
472        $objWriter->writeElement('a:t', $subject->getText());
473
474        $objWriter->endElement();
475
476        // a:endParaRPr
477        $objWriter->startElement('a:endParaRPr');
478        $objWriter->writeAttribute('lang', 'en-US');
479        $objWriter->writeAttribute('dirty', '0');
480        $objWriter->endElement();
481
482        $objWriter->endElement();
483
484        $objWriter->endElement();
485
486        $objWriter->endElement();
487
488        // Write layout
489        $this->writeLayout($objWriter, $subject);
490
491        // c:overlay
492        $objWriter->startElement('c:overlay');
493        $objWriter->writeAttribute('val', '0');
494        $objWriter->endElement();
495
496        $objWriter->endElement();
497    }
498
499    /**
500     * Write Plot Area.
501     *
502     * @param XMLWriter $objWriter XML Writer
503     */
504    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
505    {
506        // c:plotArea
507        $objWriter->startElement('c:plotArea');
508
509        // Write layout
510        $this->writeLayout($objWriter, $subject);
511
512        // Write chart
513        $chartType = $subject->getType();
514        if ($chartType instanceof Area) {
515            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
516        } elseif ($chartType instanceof Bar) {
517            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
518        } elseif ($chartType instanceof Bar3D) {
519            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
520        } elseif ($chartType instanceof Doughnut) {
521            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
522        } elseif ($chartType instanceof Pie) {
523            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
524        } elseif ($chartType instanceof Pie3D) {
525            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
526        } elseif ($chartType instanceof Line) {
527            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
528        } elseif ($chartType instanceof Radar) {
529            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
530        } elseif ($chartType instanceof Scatter) {
531            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
532        } else {
533            throw new UndefinedChartTypeException();
534        }
535
536        // Write X axis?
537        if ($chartType->hasAxisX()) {
538            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
539        }
540
541        // Write Y axis?
542        if ($chartType->hasAxisY()) {
543            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
544        }
545
546        $objWriter->endElement();
547    }
548
549    /**
550     * Write Legend.
551     *
552     * @param XMLWriter $objWriter XML Writer
553     * @param Chart\Legend $subject
554     */
555    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
556    {
557        // c:legend
558        $objWriter->startElement('c:legend');
559
560        // c:legendPos
561        $objWriter->startElement('c:legendPos');
562        $objWriter->writeAttribute('val', $subject->getPosition());
563        $objWriter->endElement();
564
565        // Write layout
566        $this->writeLayout($objWriter, $subject);
567
568        // c:overlay
569        $objWriter->startElement('c:overlay');
570        $objWriter->writeAttribute('val', '0');
571        $objWriter->endElement();
572
573        // c:spPr
574        $objWriter->startElement('c:spPr');
575
576        // Fill
577        $this->writeFill($objWriter, $subject->getFill());
578
579        // Border
580        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
581            $this->writeBorder($objWriter, $subject->getBorder(), '');
582        }
583
584        $objWriter->endElement();
585
586        // c:txPr
587        $objWriter->startElement('c:txPr');
588
589        // a:bodyPr
590        $objWriter->writeElement('a:bodyPr', null);
591
592        // a:lstStyle
593        $objWriter->writeElement('a:lstStyle', null);
594
595        // a:p
596        $objWriter->startElement('a:p');
597
598        // a:pPr
599        $objWriter->startElement('a:pPr');
600        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
601        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
602        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
603        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
604        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
605        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
606
607        // a:defRPr
608        $objWriter->startElement('a:defRPr');
609
610        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
611        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
612        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
613        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
614        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
615        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
616        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
617
618        // Font - a:solidFill
619        $objWriter->startElement('a:solidFill');
620
621        $this->writeColor($objWriter, $subject->getFont()->getColor());
622
623        $objWriter->endElement();
624
625        // Font - a:latin
626        $objWriter->startElement('a:latin');
627        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
628        $objWriter->endElement();
629
630        $objWriter->endElement();
631
632        $objWriter->endElement();
633
634        // a:endParaRPr
635        $objWriter->startElement('a:endParaRPr');
636        $objWriter->writeAttribute('lang', 'en-US');
637        $objWriter->writeAttribute('dirty', '0');
638        $objWriter->endElement();
639
640        $objWriter->endElement();
641
642        $objWriter->endElement();
643
644        $objWriter->endElement();
645    }
646
647    /**
648     * Write Layout.
649     *
650     * @param XMLWriter $objWriter XML Writer
651     * @param Legend|PlotArea|Title $subject
652     */
653    protected function writeLayout(XMLWriter $objWriter, $subject): void
654    {
655        // c:layout
656        $objWriter->startElement('c:layout');
657
658        // c:manualLayout
659        $objWriter->startElement('c:manualLayout');
660        // c:xMode
661        $objWriter->startElement('c:xMode');
662        $objWriter->writeAttribute('val', 'edge');
663        $objWriter->endElement();
664
665        // c:yMode
666        $objWriter->startElement('c:yMode');
667        $objWriter->writeAttribute('val', 'edge');
668        $objWriter->endElement();
669
670        if (0 != $subject->getOffsetX()) {
671            // c:x
672            $objWriter->startElement('c:x');
673            $objWriter->writeAttribute('val', $subject->getOffsetX());
674            $objWriter->endElement();
675        }
676
677        if (0 != $subject->getOffsetY()) {
678            // c:y
679            $objWriter->startElement('c:y');
680            $objWriter->writeAttribute('val', $subject->getOffsetY());
681            $objWriter->endElement();
682        }
683
684        if (0 != $subject->getWidth()) {
685            // c:w
686            $objWriter->startElement('c:w');
687            $objWriter->writeAttribute('val', $subject->getWidth());
688            $objWriter->endElement();
689        }
690
691        if (0 != $subject->getHeight()) {
692            // c:h
693            $objWriter->startElement('c:h');
694            $objWriter->writeAttribute('val', $subject->getHeight());
695            $objWriter->endElement();
696        }
697
698        $objWriter->endElement();
699        $objWriter->endElement();
700    }
701
702    /**
703     * Write Type Area.
704     *
705     * @param XMLWriter $objWriter XML Writer
706     * @param Chart\Type\Area $subject
707     */
708    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
709    {
710        // c:lineChart
711        $objWriter->startElement('c:areaChart');
712
713        // c:grouping
714        $objWriter->startElement('c:grouping');
715        $objWriter->writeAttribute('val', 'standard');
716        $objWriter->endElement();
717
718        // Write series
719        $seriesIndex = 0;
720        foreach ($subject->getSeries() as $series) {
721            // c:ser
722            $objWriter->startElement('c:ser');
723
724            // c:ser > c:idx
725            $objWriter->startElement('c:idx');
726            $objWriter->writeAttribute('val', $seriesIndex);
727            $objWriter->endElement();
728
729            // c:ser > c:order
730            $objWriter->startElement('c:order');
731            $objWriter->writeAttribute('val', $seriesIndex);
732            $objWriter->endElement();
733
734            // c:ser > c:tx
735            $objWriter->startElement('c:tx');
736            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
737            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
738            $objWriter->endElement();
739
740            // c:ser > c:dLbls
741            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
742            $objWriter->startElement('c:dLbls');
743
744            // c:ser > c:dLbls > c:showVal
745            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
746
747            // c:ser > c:dLbls > c:showCatName
748            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
749
750            // c:ser > c:dLbls > c:showSerName
751            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
752
753            // c:ser > c:dLbls > c:showPercent
754            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
755
756            // c:ser > ##c:dLbls
757            $objWriter->endElement();
758
759            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
760                // c:spPr
761                $objWriter->startElement('c:spPr');
762                // Write fill
763                $this->writeFill($objWriter, $series->getFill());
764                // ## c:spPr
765                $objWriter->endElement();
766            }
767
768            // Write X axis data
769            $axisXData = array_keys($series->getValues());
770
771            // c:cat
772            $objWriter->startElement('c:cat');
773            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
774            $objWriter->endElement();
775
776            // Write Y axis data
777            $axisYData = array_values($series->getValues());
778
779            // c:val
780            $objWriter->startElement('c:val');
781            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
782            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
783            $objWriter->endElement();
784
785            $objWriter->endElement();
786
787            ++$seriesIndex;
788        }
789
790        // c:axId
791        $objWriter->startElement('c:axId');
792        $objWriter->writeAttribute('val', '52743552');
793        $objWriter->endElement();
794
795        // c:axId
796        $objWriter->startElement('c:axId');
797        $objWriter->writeAttribute('val', '52749440');
798        $objWriter->endElement();
799
800        $objWriter->endElement();
801    }
802
803    /**
804     * Write Type Bar.
805     *
806     * @param XMLWriter $objWriter XML Writer
807     * @param Chart\Type\Bar $subject
808     */
809    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
810    {
811        // c:barChart
812        $objWriter->startElement('c:barChart');
813
814        // c:barDir
815        $objWriter->startElement('c:barDir');
816        $objWriter->writeAttribute('val', $subject->getBarDirection());
817        $objWriter->endElement();
818
819        // c:grouping
820        $objWriter->startElement('c:grouping');
821        $objWriter->writeAttribute('val', $subject->getBarGrouping());
822        $objWriter->endElement();
823
824        // Write series
825        $seriesIndex = 0;
826        foreach ($subject->getSeries() as $series) {
827            // c:ser
828            $objWriter->startElement('c:ser');
829
830            // c:idx
831            $objWriter->startElement('c:idx');
832            $objWriter->writeAttribute('val', $seriesIndex);
833            $objWriter->endElement();
834
835            // c:order
836            $objWriter->startElement('c:order');
837            $objWriter->writeAttribute('val', $seriesIndex);
838            $objWriter->endElement();
839
840            // c:tx
841            $objWriter->startElement('c:tx');
842            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
843            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
844            $objWriter->endElement();
845
846            // Fills for points?
847            $dataPointFills = $series->getDataPointFills();
848            foreach ($dataPointFills as $key => $value) {
849                // c:dPt
850                $objWriter->startElement('c:dPt');
851
852                // c:idx
853                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
854
855                if (Fill::FILL_NONE != $value->getFillType()) {
856                    // c:spPr
857                    $objWriter->startElement('c:spPr');
858                    // Write fill
859                    $this->writeFill($objWriter, $value);
860                    // ## c:spPr
861                    $objWriter->endElement();
862                }
863
864                // ## c:dPt
865                $objWriter->endElement();
866            }
867
868            // c:dLbls
869            $objWriter->startElement('c:dLbls');
870
871            if ($series->hasDlblNumFormat()) {
872                //c:numFmt
873                $objWriter->startElement('c:numFmt');
874                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
875                $objWriter->writeAttribute('sourceLinked', '0');
876                $objWriter->endElement();
877            }
878
879            // c:txPr
880            $objWriter->startElement('c:txPr');
881
882            // a:bodyPr
883            $objWriter->writeElement('a:bodyPr');
884
885            // a:lstStyle
886            $objWriter->writeElement('a:lstStyle');
887
888            // a:p
889            $objWriter->startElement('a:p');
890
891            // a:pPr
892            $objWriter->startElement('a:pPr');
893
894            // a:defRPr
895            $objWriter->startElement('a:defRPr');
896            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
897            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
898            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
899            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
900            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
901            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
902            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
903
904            // a:solidFill
905            $objWriter->startElement('a:solidFill');
906            $this->writeColor($objWriter, $series->getFont()->getColor());
907            $objWriter->endElement();
908
909            // a:latin
910            $objWriter->startElement('a:latin');
911            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
912            $objWriter->endElement();
913
914            // a:ea
915            $objWriter->startElement('a:ea');
916            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
917            $objWriter->endElement();
918
919            // >a:defRPr
920            $objWriter->endElement();
921            // >a:pPr
922            $objWriter->endElement();
923
924            // a:endParaRPr
925            $objWriter->startElement('a:endParaRPr');
926            $objWriter->writeAttribute('lang', 'en-US');
927            $objWriter->writeAttribute('dirty', '0');
928            $objWriter->endElement();
929
930            // >a:p
931            $objWriter->endElement();
932            // >a:lstStyle
933            $objWriter->endElement();
934
935            // c:dLblPos
936            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
937
938            // c:showVal
939            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
940
941            // c:showCatName
942            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
943
944            // c:showSerName
945            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
946
947            // c:showPercent
948            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
949
950            // c:separator
951            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
952
953            // c:showLeaderLines
954            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
955
956            $objWriter->endElement();
957
958            // c:spPr
959            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
960                // c:spPr
961                $objWriter->startElement('c:spPr');
962                // Write fill
963                $this->writeFill($objWriter, $series->getFill());
964                // ## c:spPr
965                $objWriter->endElement();
966            }
967
968            // Write X axis data
969            $axisXData = array_keys($series->getValues());
970
971            // c:cat
972            $objWriter->startElement('c:cat');
973            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
974            $objWriter->endElement();
975
976            // Write Y axis data
977            $axisYData = array_values($series->getValues());
978
979            // c:val
980            $objWriter->startElement('c:val');
981            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
982            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
983            $objWriter->endElement();
984
985            $objWriter->endElement();
986
987            ++$seriesIndex;
988        }
989
990        // c:gapWidth
991        $objWriter->startElement('c:gapWidth');
992        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
993        $objWriter->endElement();
994
995        // c:overlap
996        $objWriter->startElement('c:overlap');
997        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
998        $objWriter->endElement();
999
1000        // c:axId
1001        $objWriter->startElement('c:axId');
1002        $objWriter->writeAttribute('val', '52743552');
1003        $objWriter->endElement();
1004
1005        // c:axId
1006        $objWriter->startElement('c:axId');
1007        $objWriter->writeAttribute('val', '52749440');
1008        $objWriter->endElement();
1009
1010        // c:extLst
1011        $objWriter->startElement('c:extLst');
1012        $objWriter->endElement();
1013
1014        $objWriter->endElement();
1015    }
1016
1017    /**
1018     * Write Type Bar3D.
1019     *
1020     * @param XMLWriter $objWriter XML Writer
1021     * @param Chart\Type\Bar3D $subject
1022     */
1023    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1024    {
1025        // c:bar3DChart
1026        $objWriter->startElement('c:bar3DChart');
1027
1028        // c:barDir
1029        $objWriter->startElement('c:barDir');
1030        $objWriter->writeAttribute('val', $subject->getBarDirection());
1031        $objWriter->endElement();
1032
1033        // c:grouping
1034        $objWriter->startElement('c:grouping');
1035        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1036        $objWriter->endElement();
1037
1038        // Write series
1039        $seriesIndex = 0;
1040        foreach ($subject->getSeries() as $series) {
1041            // c:ser
1042            $objWriter->startElement('c:ser');
1043
1044            // c:idx
1045            $objWriter->startElement('c:idx');
1046            $objWriter->writeAttribute('val', $seriesIndex);
1047            $objWriter->endElement();
1048
1049            // c:order
1050            $objWriter->startElement('c:order');
1051            $objWriter->writeAttribute('val', $seriesIndex);
1052            $objWriter->endElement();
1053
1054            // c:tx
1055            $objWriter->startElement('c:tx');
1056            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1057            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1058            $objWriter->endElement();
1059
1060            // Fills for points?
1061            $dataPointFills = $series->getDataPointFills();
1062            foreach ($dataPointFills as $key => $value) {
1063                // c:dPt
1064                $objWriter->startElement('c:dPt');
1065
1066                // c:idx
1067                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1068
1069                if (Fill::FILL_NONE != $value->getFillType()) {
1070                    // c:spPr
1071                    $objWriter->startElement('c:spPr');
1072                    // Write fill
1073                    $this->writeFill($objWriter, $value);
1074                    // ## c:spPr
1075                    $objWriter->endElement();
1076                }
1077
1078                // ## c:dPt
1079                $objWriter->endElement();
1080            }
1081
1082            // c:dLbls
1083            $objWriter->startElement('c:dLbls');
1084
1085            // c:txPr
1086            $objWriter->startElement('c:txPr');
1087
1088            // a:bodyPr
1089            $objWriter->writeElement('a:bodyPr', null);
1090
1091            // a:lstStyle
1092            $objWriter->writeElement('a:lstStyle', null);
1093
1094            // a:p
1095            $objWriter->startElement('a:p');
1096
1097            // a:pPr
1098            $objWriter->startElement('a:pPr');
1099
1100            // a:defRPr
1101            $objWriter->startElement('a:defRPr');
1102
1103            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1104            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1105            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1106            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1107            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1108            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1109            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1110
1111            // Font - a:solidFill
1112            $objWriter->startElement('a:solidFill');
1113
1114            $this->writeColor($objWriter, $series->getFont()->getColor());
1115
1116            $objWriter->endElement();
1117
1118            // Font - a:latin
1119            $objWriter->startElement('a:latin');
1120            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1121            $objWriter->endElement();
1122            // a:ea
1123            $objWriter->startElement('a:ea');
1124            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1125            $objWriter->endElement();
1126
1127            $objWriter->endElement();
1128
1129            $objWriter->endElement();
1130
1131            // a:endParaRPr
1132            $objWriter->startElement('a:endParaRPr');
1133            $objWriter->writeAttribute('lang', 'en-US');
1134            $objWriter->writeAttribute('dirty', '0');
1135            $objWriter->endElement();
1136
1137            $objWriter->endElement();
1138
1139            $objWriter->endElement();
1140
1141            // c:showVal
1142            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1143
1144            // c:showCatName
1145            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1146
1147            // c:showSerName
1148            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1149
1150            // c:showPercent
1151            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1152
1153            // c:showLeaderLines
1154            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1155
1156            $objWriter->endElement();
1157
1158            // c:spPr
1159            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1160                // c:spPr
1161                $objWriter->startElement('c:spPr');
1162                // Write fill
1163                $this->writeFill($objWriter, $series->getFill());
1164                // ## c:spPr
1165                $objWriter->endElement();
1166            }
1167
1168            // Write X axis data
1169            $axisXData = array_keys($series->getValues());
1170
1171            // c:cat
1172            $objWriter->startElement('c:cat');
1173            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1174            $objWriter->endElement();
1175
1176            // Write Y axis data
1177            $axisYData = array_values($series->getValues());
1178
1179            // c:val
1180            $objWriter->startElement('c:val');
1181            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1182            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1183            $objWriter->endElement();
1184
1185            $objWriter->endElement();
1186
1187            ++$seriesIndex;
1188        }
1189
1190        // c:gapWidth
1191        $objWriter->startElement('c:gapWidth');
1192        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1193        $objWriter->endElement();
1194
1195        // c:axId
1196        $objWriter->startElement('c:axId');
1197        $objWriter->writeAttribute('val', '52743552');
1198        $objWriter->endElement();
1199
1200        // c:axId
1201        $objWriter->startElement('c:axId');
1202        $objWriter->writeAttribute('val', '52749440');
1203        $objWriter->endElement();
1204
1205        // c:axId
1206        $objWriter->startElement('c:axId');
1207        $objWriter->writeAttribute('val', '0');
1208        $objWriter->endElement();
1209
1210        $objWriter->endElement();
1211    }
1212
1213    /**
1214     * Write Type Pie.
1215     *
1216     * @param XMLWriter $objWriter XML Writer
1217     */
1218    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1219    {
1220        // c:pieChart
1221        $objWriter->startElement('c:doughnutChart');
1222
1223        // c:varyColors
1224        $objWriter->startElement('c:varyColors');
1225        $objWriter->writeAttribute('val', '1');
1226        $objWriter->endElement();
1227
1228        // Write series
1229        $seriesIndex = 0;
1230        foreach ($subject->getSeries() as $series) {
1231            // c:ser
1232            $objWriter->startElement('c:ser');
1233
1234            // c:idx
1235            $objWriter->startElement('c:idx');
1236            $objWriter->writeAttribute('val', $seriesIndex);
1237            $objWriter->endElement();
1238
1239            // c:order
1240            $objWriter->startElement('c:order');
1241            $objWriter->writeAttribute('val', $seriesIndex);
1242            $objWriter->endElement();
1243
1244            // c:tx
1245            $objWriter->startElement('c:tx');
1246            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1247            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1248            $objWriter->endElement();
1249
1250            // Fills for points?
1251            $dataPointFills = $series->getDataPointFills();
1252            foreach ($dataPointFills as $key => $value) {
1253                // c:dPt
1254                $objWriter->startElement('c:dPt');
1255                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1256                // c:dPt/c:spPr
1257                $objWriter->startElement('c:spPr');
1258                $this->writeFill($objWriter, $value);
1259                // c:dPt/##c:spPr
1260                $objWriter->endElement();
1261                // ##c:dPt
1262                $objWriter->endElement();
1263            }
1264
1265            // Write X axis data
1266            $axisXData = array_keys($series->getValues());
1267
1268            // c:cat
1269            $objWriter->startElement('c:cat');
1270            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1271            $objWriter->endElement();
1272
1273            // Write Y axis data
1274            $axisYData = array_values($series->getValues());
1275
1276            // c:val
1277            $objWriter->startElement('c:val');
1278            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1279            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1280            $objWriter->endElement();
1281
1282            $objWriter->endElement();
1283
1284            ++$seriesIndex;
1285        }
1286
1287        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1288            // c:dLbls
1289            $objWriter->startElement('c:dLbls');
1290
1291            if ($series->hasDlblNumFormat()) {
1292                //c:numFmt
1293                $objWriter->startElement('c:numFmt');
1294                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1295                $objWriter->writeAttribute('sourceLinked', '0');
1296                $objWriter->endElement();
1297            }
1298
1299            // c:dLbls\c:txPr
1300            $objWriter->startElement('c:txPr');
1301            $objWriter->writeElement('a:bodyPr', null);
1302            $objWriter->writeElement('a:lstStyle', null);
1303
1304            // c:dLbls\c:txPr\a:p
1305            $objWriter->startElement('a:p');
1306
1307            // c:dLbls\c:txPr\a:p\a:pPr
1308            $objWriter->startElement('a:pPr');
1309
1310            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1311            $objWriter->startElement('a:defRPr');
1312            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1313            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1314            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1315            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1316            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1317            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1318            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1319
1320            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1321            $objWriter->startElement('a:solidFill');
1322            $this->writeColor($objWriter, $series->getFont()->getColor());
1323            $objWriter->endElement();
1324
1325            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1326            $objWriter->startElement('a:latin');
1327            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1328            $objWriter->endElement();
1329            // a:ea
1330            $objWriter->startElement('a:ea');
1331            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1332            $objWriter->endElement();
1333
1334            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1335            $objWriter->endElement();
1336            // c:dLbls\c:txPr\a:p\a:pPr\
1337            $objWriter->endElement();
1338
1339            // c:dLbls\c:txPr\a:p\a:endParaRPr
1340            $objWriter->startElement('a:endParaRPr');
1341            $objWriter->writeAttribute('lang', 'en-US');
1342            $objWriter->writeAttribute('dirty', '0');
1343            $objWriter->endElement();
1344
1345            // c:dLbls\c:txPr\a:p\
1346            $objWriter->endElement();
1347            // c:dLbls\c:txPr\
1348            $objWriter->endElement();
1349
1350            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1351            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1352            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1353            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1354            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1355            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1356            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1357
1358            $separator = $series->getSeparator();
1359            if (!empty($separator) && PHP_EOL != $separator) {
1360                // c:dLbls\c:separator
1361                $objWriter->writeElement('c:separator', $separator);
1362            }
1363
1364            // c:dLbls\
1365            $objWriter->endElement();
1366        }
1367
1368        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1369        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1370
1371        $objWriter->endElement();
1372    }
1373
1374    /**
1375     * Write Type Pie.
1376     *
1377     * @param XMLWriter $objWriter XML Writer
1378     */
1379    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1380    {
1381        // c:pieChart
1382        $objWriter->startElement('c:pieChart');
1383
1384        // c:varyColors
1385        $objWriter->startElement('c:varyColors');
1386        $objWriter->writeAttribute('val', '1');
1387        $objWriter->endElement();
1388
1389        // Write series
1390        $seriesIndex = 0;
1391        foreach ($subject->getSeries() as $series) {
1392            // c:ser
1393            $objWriter->startElement('c:ser');
1394
1395            // c:idx
1396            $objWriter->startElement('c:idx');
1397            $objWriter->writeAttribute('val', $seriesIndex);
1398            $objWriter->endElement();
1399
1400            // c:order
1401            $objWriter->startElement('c:order');
1402            $objWriter->writeAttribute('val', $seriesIndex);
1403            $objWriter->endElement();
1404
1405            // c:tx
1406            $objWriter->startElement('c:tx');
1407            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1408            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1409            $objWriter->endElement();
1410
1411            // Fills for points?
1412            $dataPointFills = $series->getDataPointFills();
1413            foreach ($dataPointFills as $key => $value) {
1414                // c:dPt
1415                $objWriter->startElement('c:dPt');
1416                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1417                // c:dPt/c:spPr
1418                $objWriter->startElement('c:spPr');
1419                $this->writeFill($objWriter, $value);
1420                // c:dPt/##c:spPr
1421                $objWriter->endElement();
1422                // ##c:dPt
1423                $objWriter->endElement();
1424            }
1425
1426            // c:dLbls
1427            $objWriter->startElement('c:dLbls');
1428
1429            if ($series->hasDlblNumFormat()) {
1430                //c:numFmt
1431                $objWriter->startElement('c:numFmt');
1432                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1433                $objWriter->writeAttribute('sourceLinked', '0');
1434                $objWriter->endElement();
1435            }
1436
1437            // c:txPr
1438            $objWriter->startElement('c:txPr');
1439
1440            // a:bodyPr
1441            $objWriter->writeElement('a:bodyPr', null);
1442
1443            // a:lstStyle
1444            $objWriter->writeElement('a:lstStyle', null);
1445
1446            // a:p
1447            $objWriter->startElement('a:p');
1448
1449            // a:pPr
1450            $objWriter->startElement('a:pPr');
1451
1452            // a:defRPr
1453            $objWriter->startElement('a:defRPr');
1454
1455            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1456            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1457            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1458            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1459            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1460            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1461            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1462
1463            // Font - a:solidFill
1464            $objWriter->startElement('a:solidFill');
1465
1466            $this->writeColor($objWriter, $series->getFont()->getColor());
1467
1468            $objWriter->endElement();
1469
1470            // Font - a:latin
1471            $objWriter->startElement('a:latin');
1472            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1473            $objWriter->endElement();
1474            // a:ea
1475            $objWriter->startElement('a:ea');
1476            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1477            $objWriter->endElement();
1478
1479            $objWriter->endElement();
1480
1481            $objWriter->endElement();
1482
1483            // a:endParaRPr
1484            $objWriter->startElement('a:endParaRPr');
1485            $objWriter->writeAttribute('lang', 'en-US');
1486            $objWriter->writeAttribute('dirty', '0');
1487            $objWriter->endElement();
1488
1489            $objWriter->endElement();
1490
1491            $objWriter->endElement();
1492
1493            // c:dLblPos
1494            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1495
1496            // c:showLegendKey
1497            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1498
1499            // c:showVal
1500            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1501
1502            // c:showCatName
1503            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1504
1505            // c:showSerName
1506            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1507
1508            // c:showPercent
1509            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1510
1511            // c:showLeaderLines
1512            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1513
1514            $objWriter->endElement();
1515
1516            // Write X axis data
1517            $axisXData = array_keys($series->getValues());
1518
1519            // c:cat
1520            $objWriter->startElement('c:cat');
1521            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1522            $objWriter->endElement();
1523
1524            // Write Y axis data
1525            $axisYData = array_values($series->getValues());
1526
1527            // c:val
1528            $objWriter->startElement('c:val');
1529            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1530            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1531            $objWriter->endElement();
1532
1533            $objWriter->endElement();
1534
1535            ++$seriesIndex;
1536        }
1537
1538        $objWriter->endElement();
1539    }
1540
1541    /**
1542     * Write Type Pie3D.
1543     *
1544     * @param XMLWriter $objWriter XML Writer
1545     */
1546    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1547    {
1548        // c:pie3DChart
1549        $objWriter->startElement('c:pie3DChart');
1550
1551        // c:varyColors
1552        $objWriter->startElement('c:varyColors');
1553        $objWriter->writeAttribute('val', '1');
1554        $objWriter->endElement();
1555
1556        // Write series
1557        $seriesIndex = 0;
1558        foreach ($subject->getSeries() as $series) {
1559            // c:ser
1560            $objWriter->startElement('c:ser');
1561
1562            // c:idx
1563            $objWriter->startElement('c:idx');
1564            $objWriter->writeAttribute('val', $seriesIndex);
1565            $objWriter->endElement();
1566
1567            // c:order
1568            $objWriter->startElement('c:order');
1569            $objWriter->writeAttribute('val', $seriesIndex);
1570            $objWriter->endElement();
1571
1572            // c:tx
1573            $objWriter->startElement('c:tx');
1574            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1575            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1576            $objWriter->endElement();
1577
1578            // c:explosion
1579            $objWriter->startElement('c:explosion');
1580            $objWriter->writeAttribute('val', $subject->getExplosion());
1581            $objWriter->endElement();
1582
1583            // Fills for points?
1584            $dataPointFills = $series->getDataPointFills();
1585            foreach ($dataPointFills as $key => $value) {
1586                // c:dPt
1587                $objWriter->startElement('c:dPt');
1588                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1589                // c:dPt/c:spPr
1590                $objWriter->startElement('c:spPr');
1591                $this->writeFill($objWriter, $value);
1592                // c:dPt/##c:spPr
1593                $objWriter->endElement();
1594                // ##c:dPt
1595                $objWriter->endElement();
1596            }
1597
1598            // c:dLbls
1599            $objWriter->startElement('c:dLbls');
1600
1601            // c:txPr
1602            $objWriter->startElement('c:txPr');
1603
1604            // a:bodyPr
1605            $objWriter->writeElement('a:bodyPr', null);
1606
1607            // a:lstStyle
1608            $objWriter->writeElement('a:lstStyle', null);
1609
1610            // a:p
1611            $objWriter->startElement('a:p');
1612
1613            // a:pPr
1614            $objWriter->startElement('a:pPr');
1615
1616            // a:defRPr
1617            $objWriter->startElement('a:defRPr');
1618
1619            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1620            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1621            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1622            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1623            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1624            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1625            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1626
1627            // Font - a:solidFill
1628            $objWriter->startElement('a:solidFill');
1629
1630            $this->writeColor($objWriter, $series->getFont()->getColor());
1631
1632            $objWriter->endElement();
1633
1634            // Font - a:latin
1635            $objWriter->startElement('a:latin');
1636            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1637            $objWriter->endElement();
1638            // a:ea
1639            $objWriter->startElement('a:ea');
1640            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1641            $objWriter->endElement();
1642
1643            $objWriter->endElement();
1644
1645            $objWriter->endElement();
1646
1647            // a:endParaRPr
1648            $objWriter->startElement('a:endParaRPr');
1649            $objWriter->writeAttribute('lang', 'en-US');
1650            $objWriter->writeAttribute('dirty', '0');
1651            $objWriter->endElement();
1652
1653            $objWriter->endElement();
1654
1655            $objWriter->endElement();
1656
1657            // c:dLblPos
1658            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1659
1660            // c:showVal
1661            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1662
1663            // c:showCatName
1664            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1665
1666            // c:showSerName
1667            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1668
1669            // c:showPercent
1670            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1671
1672            // c:showLeaderLines
1673            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1674
1675            $objWriter->endElement();
1676
1677            // Write X axis data
1678            $axisXData = array_keys($series->getValues());
1679
1680            // c:cat
1681            $objWriter->startElement('c:cat');
1682            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1683            $objWriter->endElement();
1684
1685            // Write Y axis data
1686            $axisYData = array_values($series->getValues());
1687
1688            // c:val
1689            $objWriter->startElement('c:val');
1690            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1691            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1692            $objWriter->endElement();
1693
1694            $objWriter->endElement();
1695
1696            ++$seriesIndex;
1697        }
1698
1699        $objWriter->endElement();
1700    }
1701
1702    /**
1703     * Write Type Line.
1704     *
1705     * @param XMLWriter $objWriter XML Writer
1706     */
1707    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1708    {
1709        // c:lineChart
1710        $objWriter->startElement('c:lineChart');
1711
1712        // c:grouping
1713        $objWriter->startElement('c:grouping');
1714        $objWriter->writeAttribute('val', 'standard');
1715        $objWriter->endElement();
1716
1717        // Write series
1718        $seriesIndex = 0;
1719        foreach ($subject->getSeries() as $series) {
1720            // c:ser
1721            $objWriter->startElement('c:ser');
1722
1723            // c:idx
1724            $objWriter->startElement('c:idx');
1725            $objWriter->writeAttribute('val', $seriesIndex);
1726            $objWriter->endElement();
1727
1728            // c:order
1729            $objWriter->startElement('c:order');
1730            $objWriter->writeAttribute('val', $seriesIndex);
1731            $objWriter->endElement();
1732
1733            // c:tx
1734            $objWriter->startElement('c:tx');
1735            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1736            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1737            $objWriter->endElement();
1738
1739            // c:spPr
1740            $objWriter->startElement('c:spPr');
1741            // Write fill
1742            $this->writeFill($objWriter, $series->getFill());
1743            // Write outline
1744            $this->writeOutline($objWriter, $series->getOutline());
1745            // ## c:spPr
1746            $objWriter->endElement();
1747
1748            // Marker
1749            $this->writeSeriesMarker($objWriter, $series->getMarker());
1750
1751            // c:dLbls
1752            $objWriter->startElement('c:dLbls');
1753
1754            // c:txPr
1755            $objWriter->startElement('c:txPr');
1756
1757            // a:bodyPr
1758            $objWriter->writeElement('a:bodyPr', null);
1759
1760            // a:lstStyle
1761            $objWriter->writeElement('a:lstStyle', null);
1762
1763            // a:p
1764            $objWriter->startElement('a:p');
1765
1766            // a:pPr
1767            $objWriter->startElement('a:pPr');
1768
1769            // a:defRPr
1770            $objWriter->startElement('a:defRPr');
1771
1772            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1773            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1774            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1775            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1776            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1777            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1778            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1779
1780            // Font - a:solidFill
1781            $objWriter->startElement('a:solidFill');
1782
1783            $this->writeColor($objWriter, $series->getFont()->getColor());
1784
1785            $objWriter->endElement();
1786
1787            // Font - a:latin
1788            $objWriter->startElement('a:latin');
1789            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1790            $objWriter->endElement();
1791            // a:ea
1792            $objWriter->startElement('a:ea');
1793            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1794            $objWriter->endElement();
1795
1796            $objWriter->endElement();
1797
1798            $objWriter->endElement();
1799
1800            // a:endParaRPr
1801            $objWriter->startElement('a:endParaRPr');
1802            $objWriter->writeAttribute('lang', 'en-US');
1803            $objWriter->writeAttribute('dirty', '0');
1804            $objWriter->endElement();
1805
1806            $objWriter->endElement();
1807
1808            $objWriter->endElement();
1809
1810            // c:showVal
1811            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1812
1813            // c:showCatName
1814            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1815
1816            // c:showSerName
1817            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1818
1819            // c:showPercent
1820            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1821
1822            // c:showLeaderLines
1823            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1824
1825            // > c:dLbls
1826            $objWriter->endElement();
1827
1828            // Write X axis data
1829            $axisXData = array_keys($series->getValues());
1830
1831            // c:cat
1832            $objWriter->startElement('c:cat');
1833            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1834            $objWriter->endElement();
1835
1836            // Write Y axis data
1837            $axisYData = array_values($series->getValues());
1838
1839            // c:val
1840            $objWriter->startElement('c:val');
1841            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1842            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1843            $objWriter->endElement();
1844
1845            // c:smooth
1846            $objWriter->startElement('c:smooth');
1847            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1848            $objWriter->endElement();
1849
1850            $objWriter->endElement();
1851
1852            ++$seriesIndex;
1853        }
1854
1855        // c:marker
1856        $objWriter->startElement('c:marker');
1857        $objWriter->writeAttribute('val', '1');
1858        $objWriter->endElement();
1859
1860        // c:axId
1861        $objWriter->startElement('c:axId');
1862        $objWriter->writeAttribute('val', '52743552');
1863        $objWriter->endElement();
1864
1865        // c:axId
1866        $objWriter->startElement('c:axId');
1867        $objWriter->writeAttribute('val', '52749440');
1868        $objWriter->endElement();
1869
1870        $objWriter->endElement();
1871    }
1872
1873    /**
1874     * Write Type Radar.
1875     *
1876     * @param XMLWriter $objWriter XML Writer
1877     */
1878    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1879    {
1880        // c:scatterChart
1881        $objWriter->startElement('c:radarChart');
1882
1883        // c:radarStyle
1884        $objWriter->startElement('c:radarStyle');
1885        $objWriter->writeAttribute('val', 'marker');
1886        $objWriter->endElement();
1887
1888        // c:varyColors
1889        $objWriter->startElement('c:varyColors');
1890        $objWriter->writeAttribute('val', '0');
1891        $objWriter->endElement();
1892
1893        // Write series
1894        $seriesIndex = 0;
1895        foreach ($subject->getSeries() as $series) {
1896            // c:ser
1897            $objWriter->startElement('c:ser');
1898
1899            // c:idx
1900            $objWriter->startElement('c:idx');
1901            $objWriter->writeAttribute('val', $seriesIndex);
1902            $objWriter->endElement();
1903
1904            // c:order
1905            $objWriter->startElement('c:order');
1906            $objWriter->writeAttribute('val', $seriesIndex);
1907            $objWriter->endElement();
1908
1909            // c:tx
1910            $objWriter->startElement('c:tx');
1911            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1912            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1913            $objWriter->endElement();
1914
1915            // c:spPr
1916            $objWriter->startElement('c:spPr');
1917            // Write fill
1918            $this->writeFill($objWriter, $series->getFill());
1919            // Write outline
1920            $this->writeOutline($objWriter, $series->getOutline());
1921            // ## c:spPr
1922            $objWriter->endElement();
1923
1924            // Marker
1925            $this->writeSeriesMarker($objWriter, $series->getMarker());
1926
1927            // c:dLbls
1928            $objWriter->startElement('c:dLbls');
1929
1930            // c:txPr
1931            $objWriter->startElement('c:txPr');
1932
1933            // a:bodyPr
1934            $objWriter->writeElement('a:bodyPr', null);
1935
1936            // a:lstStyle
1937            $objWriter->writeElement('a:lstStyle', null);
1938
1939            // a:p
1940            $objWriter->startElement('a:p');
1941
1942            // a:pPr
1943            $objWriter->startElement('a:pPr');
1944
1945            // a:defRPr
1946            $objWriter->startElement('a:defRPr');
1947
1948            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1949            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1950            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1951            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1952            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1953            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1954            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1955
1956            // Font - a:solidFill
1957            $objWriter->startElement('a:solidFill');
1958
1959            $this->writeColor($objWriter, $series->getFont()->getColor());
1960
1961            $objWriter->endElement();
1962
1963            // Font - a:latin
1964            $objWriter->startElement('a:latin');
1965            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1966            $objWriter->endElement();
1967            // a:ea
1968            $objWriter->startElement('a:ea');
1969            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1970            $objWriter->endElement();
1971
1972            $objWriter->endElement();
1973
1974            $objWriter->endElement();
1975
1976            // a:endParaRPr
1977            $objWriter->startElement('a:endParaRPr');
1978            $objWriter->writeAttribute('lang', 'en-US');
1979            $objWriter->writeAttribute('dirty', '0');
1980            $objWriter->endElement();
1981
1982            $objWriter->endElement();
1983
1984            $objWriter->endElement();
1985
1986            // c:showLegendKey
1987            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1988
1989            // c:showVal
1990            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1991
1992            // c:showCatName
1993            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1994
1995            // c:showSerName
1996            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1997
1998            // c:showPercent
1999            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2000
2001            // c:showLeaderLines
2002            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2003
2004            $objWriter->endElement();
2005
2006            // Write X axis data
2007            $axisXData = array_keys($series->getValues());
2008
2009            // c:cat
2010            $objWriter->startElement('c:cat');
2011            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2012            $objWriter->endElement();
2013
2014            // Write Y axis data
2015            $axisYData = array_values($series->getValues());
2016
2017            // c:val
2018            $objWriter->startElement('c:val');
2019            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2020            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2021            $objWriter->endElement();
2022
2023            $objWriter->endElement();
2024
2025            ++$seriesIndex;
2026        }
2027
2028        // c:axId
2029        $objWriter->startElement('c:axId');
2030        $objWriter->writeAttribute('val', '52743552');
2031        $objWriter->endElement();
2032
2033        // c:axId
2034        $objWriter->startElement('c:axId');
2035        $objWriter->writeAttribute('val', '52749440');
2036        $objWriter->endElement();
2037
2038        $objWriter->endElement();
2039    }
2040
2041    /**
2042     * Write Type Scatter.
2043     */
2044    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2045    {
2046        // c:scatterChart
2047        $objWriter->startElement('c:scatterChart');
2048
2049        // c:scatterStyle
2050        $objWriter->startElement('c:scatterStyle');
2051        $objWriter->writeAttribute('val', 'lineMarker');
2052        $objWriter->endElement();
2053
2054        // c:varyColors
2055        $objWriter->startElement('c:varyColors');
2056        $objWriter->writeAttribute('val', '0');
2057        $objWriter->endElement();
2058
2059        // Write series
2060        $seriesIndex = 0;
2061        foreach ($subject->getSeries() as $series) {
2062            // c:ser
2063            $objWriter->startElement('c:ser');
2064
2065            // c:idx
2066            $objWriter->startElement('c:idx');
2067            $objWriter->writeAttribute('val', $seriesIndex);
2068            $objWriter->endElement();
2069
2070            // c:order
2071            $objWriter->startElement('c:order');
2072            $objWriter->writeAttribute('val', $seriesIndex);
2073            $objWriter->endElement();
2074
2075            // c:tx
2076            $objWriter->startElement('c:tx');
2077            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
2078            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2079            $objWriter->endElement();
2080
2081            // c:spPr
2082            $objWriter->startElement('c:spPr');
2083            // Write fill
2084            $this->writeFill($objWriter, $series->getFill());
2085            // Write outline
2086            $this->writeOutline($objWriter, $series->getOutline());
2087            // ## c:spPr
2088            $objWriter->endElement();
2089
2090            // Marker
2091            $this->writeSeriesMarker($objWriter, $series->getMarker());
2092
2093            // c:dLbls
2094            $objWriter->startElement('c:dLbls');
2095
2096            // c:txPr
2097            $objWriter->startElement('c:txPr');
2098
2099            // a:bodyPr
2100            $objWriter->writeElement('a:bodyPr', null);
2101
2102            // a:lstStyle
2103            $objWriter->writeElement('a:lstStyle', null);
2104
2105            // a:p
2106            $objWriter->startElement('a:p');
2107
2108            // a:pPr
2109            $objWriter->startElement('a:pPr');
2110
2111            // a:defRPr
2112            $objWriter->startElement('a:defRPr');
2113
2114            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2115            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2116            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2117            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2118            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2119            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2120            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2121
2122            // Font - a:solidFill
2123            $objWriter->startElement('a:solidFill');
2124
2125            $this->writeColor($objWriter, $series->getFont()->getColor());
2126
2127            $objWriter->endElement();
2128
2129            // Font - a:latin
2130            $objWriter->startElement('a:latin');
2131            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2132            $objWriter->endElement();
2133            // a:ea
2134            $objWriter->startElement('a:ea');
2135            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2136            $objWriter->endElement();
2137
2138            $objWriter->endElement();
2139
2140            $objWriter->endElement();
2141
2142            // a:endParaRPr
2143            $objWriter->startElement('a:endParaRPr');
2144            $objWriter->writeAttribute('lang', 'en-US');
2145            $objWriter->writeAttribute('dirty', '0');
2146            $objWriter->endElement();
2147
2148            $objWriter->endElement();
2149
2150            $objWriter->endElement();
2151
2152            // c:showLegendKey
2153            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2154
2155            // c:showVal
2156            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2157
2158            // c:showCatName
2159            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2160
2161            // c:showSerName
2162            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2163
2164            // c:showPercent
2165            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2166
2167            // c:separator
2168            $separator = $series->getSeparator();
2169            if (!empty($separator) && PHP_EOL != $separator) {
2170                // c:dLbls\c:separator
2171                $objWriter->writeElement('c:separator', $separator);
2172            }
2173
2174            // c:showLeaderLines
2175            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2176
2177            $objWriter->endElement();
2178
2179            // Write X axis data
2180            $axisXData = array_keys($series->getValues());
2181
2182            // c:xVal
2183            $objWriter->startElement('c:xVal');
2184            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2185            $objWriter->endElement();
2186
2187            // Write Y axis data
2188            $axisYData = array_values($series->getValues());
2189
2190            // c:yVal
2191            $objWriter->startElement('c:yVal');
2192            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2193            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2194            $objWriter->endElement();
2195
2196            // c:smooth
2197            $objWriter->startElement('c:smooth');
2198            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2199            $objWriter->endElement();
2200
2201            $objWriter->endElement();
2202
2203            ++$seriesIndex;
2204        }
2205
2206        // c:axId
2207        $objWriter->startElement('c:axId');
2208        $objWriter->writeAttribute('val', '52743552');
2209        $objWriter->endElement();
2210
2211        // c:axId
2212        $objWriter->startElement('c:axId');
2213        $objWriter->writeAttribute('val', '52749440');
2214        $objWriter->endElement();
2215
2216        $objWriter->endElement();
2217    }
2218
2219    /**
2220     * Write chart relationships to XML format.
2221     *
2222     * @return string XML Output
2223     */
2224    protected function writeChartRelationships(Chart $pChart): string
2225    {
2226        // Create XML writer
2227        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2228
2229        // XML header
2230        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2231
2232        // Relationships
2233        $objWriter->startElement('Relationships');
2234        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2235
2236        // Write spreadsheet relationship?
2237        if ($pChart->hasIncludedSpreadsheet()) {
2238            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2239        }
2240
2241        $objWriter->endElement();
2242
2243        // Return
2244        return $objWriter->getData();
2245    }
2246
2247    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2248    {
2249        // c:marker
2250        $objWriter->startElement('c:marker');
2251        // c:marker > c:symbol
2252        $objWriter->startElement('c:symbol');
2253        $objWriter->writeAttribute('val', $marker->getSymbol());
2254        $objWriter->endElement();
2255
2256        // Size if different of none
2257        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2258            $markerSize = (int) $marker->getSize();
2259            if ($markerSize < 2) {
2260                $markerSize = 2;
2261            }
2262            if ($markerSize > 72) {
2263                $markerSize = 72;
2264            }
2265
2266            /*
2267             * c:marker > c:size
2268             * Size in points
2269             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2270             */
2271            $objWriter->startElement('c:size');
2272            $objWriter->writeAttribute('val', $markerSize);
2273            $objWriter->endElement();
2274        }
2275
2276        // // c:marker > c:spPr
2277        $objWriter->startElement('c:spPr');
2278        $this->writeFill($objWriter, $marker->getFill());
2279        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2280        $objWriter->endElement();
2281
2282        // > c:marker
2283        $objWriter->endElement();
2284    }
2285
2286    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2287    {
2288        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2289            return;
2290        }
2291
2292        $crossesAt = $oAxis->getCrossesAt();
2293        $orientation = $oAxis->isReversedOrder() ? 'maxMin' : 'minMax';
2294
2295        if (Chart\Axis::AXIS_X == $typeAxis) {
2296            $mainElement = 'c:catAx';
2297            $axIdVal = '52743552';
2298            $axPosVal = $crossesAt === 'max' ? 't' : 'b';
2299            $crossAxVal = '52749440';
2300        } else {
2301            $mainElement = 'c:valAx';
2302            $axIdVal = '52749440';
2303            $axPosVal = $crossesAt === 'max' ? 'r' : 'l';
2304            $crossAxVal = '52743552';
2305        }
2306
2307        // $mainElement
2308        $objWriter->startElement($mainElement);
2309
2310        // $mainElement > c:axId
2311        $objWriter->startElement('c:axId');
2312        $objWriter->writeAttribute('val', $axIdVal);
2313        $objWriter->endElement();
2314
2315        // $mainElement > c:scaling
2316        $objWriter->startElement('c:scaling');
2317
2318        // $mainElement > c:scaling > c:orientation
2319        $objWriter->startElement('c:orientation');
2320        $objWriter->writeAttribute('val', $orientation);
2321        $objWriter->endElement();
2322
2323        if (null !== $oAxis->getMaxBounds()) {
2324            $objWriter->startElement('c:max');
2325            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2326            $objWriter->endElement();
2327        }
2328
2329        if (null !== $oAxis->getMinBounds()) {
2330            $objWriter->startElement('c:min');
2331            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2332            $objWriter->endElement();
2333        }
2334
2335        // $mainElement > ##c:scaling
2336        $objWriter->endElement();
2337
2338        // $mainElement > c:delete
2339        $objWriter->startElement('c:delete');
2340        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2341        $objWriter->endElement();
2342
2343        // $mainElement > c:axPos
2344        $objWriter->startElement('c:axPos');
2345        $objWriter->writeAttribute('val', $axPosVal);
2346        $objWriter->endElement();
2347
2348        $oMajorGridlines = $oAxis->getMajorGridlines();
2349        if ($oMajorGridlines instanceof Gridlines) {
2350            $objWriter->startElement('c:majorGridlines');
2351
2352            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2353
2354            $objWriter->endElement();
2355        }
2356
2357        $oMinorGridlines = $oAxis->getMinorGridlines();
2358        if ($oMinorGridlines instanceof Gridlines) {
2359            $objWriter->startElement('c:minorGridlines');
2360
2361            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2362
2363            $objWriter->endElement();
2364        }
2365
2366        if ('' != $oAxis->getTitle()) {
2367            // c:title
2368            $objWriter->startElement('c:title');
2369
2370            // c:tx
2371            $objWriter->startElement('c:tx');
2372
2373            // c:rich
2374            $objWriter->startElement('c:rich');
2375
2376            // a:bodyPr
2377            $objWriter->startElement('a:bodyPr');
2378            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2379            $objWriter->endElement();
2380
2381            // a:lstStyle
2382            $objWriter->writeElement('a:lstStyle', null);
2383
2384            // a:p
2385            $objWriter->startElement('a:p');
2386
2387            // a:pPr
2388            $objWriter->startElement('a:pPr');
2389
2390            // a:defRPr
2391            $objWriter->startElement('a:defRPr');
2392
2393            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2394            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2395            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2396            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2397            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2398            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2399            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2400
2401            // Font - a:solidFill
2402            $objWriter->startElement('a:solidFill');
2403            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2404            $objWriter->endElement();
2405
2406            // Font - a:latin
2407            $objWriter->startElement('a:latin');
2408            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2409            $objWriter->endElement();
2410            // a:ea
2411            $objWriter->startElement('a:ea');
2412            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2413            $objWriter->endElement();
2414
2415            $objWriter->endElement();
2416
2417            // ## a:pPr
2418            $objWriter->endElement();
2419
2420            // a:r
2421            $objWriter->startElement('a:r');
2422
2423            // a:rPr
2424            $objWriter->startElement('a:rPr');
2425            $objWriter->writeAttribute('lang', 'en-US');
2426            $objWriter->writeAttribute('dirty', '0');
2427            $objWriter->endElement();
2428
2429            // a:t
2430            $objWriter->writeElement('a:t', $oAxis->getTitle());
2431
2432            // ## a:r
2433            $objWriter->endElement();
2434
2435            // a:endParaRPr
2436            $objWriter->startElement('a:endParaRPr');
2437            $objWriter->writeAttribute('lang', 'en-US');
2438            $objWriter->writeAttribute('dirty', '0');
2439            $objWriter->endElement();
2440
2441            // ## a:p
2442            $objWriter->endElement();
2443
2444            // ## c:rich
2445            $objWriter->endElement();
2446
2447            // ## c:tx
2448            $objWriter->endElement();
2449
2450            // ## c:title
2451            $objWriter->endElement();
2452        }
2453
2454        // c:numFmt
2455        $objWriter->startElement('c:numFmt');
2456        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2457        $objWriter->writeAttribute('sourceLinked', '1');
2458        $objWriter->endElement();
2459
2460        // c:majorTickMark
2461        $objWriter->startElement('c:majorTickMark');
2462        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2463        $objWriter->endElement();
2464
2465        // c:minorTickMark
2466        $objWriter->startElement('c:minorTickMark');
2467        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2468        $objWriter->endElement();
2469
2470        // c:tickLblPos
2471        $objWriter->startElement('c:tickLblPos');
2472        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2473        $objWriter->endElement();
2474
2475        // c:spPr
2476        $objWriter->startElement('c:spPr');
2477        $this->writeOutline($objWriter, $oAxis->getOutline());
2478        $objWriter->endElement();
2479
2480        // c:txPr
2481        $objWriter->startElement('c:txPr');
2482
2483        // a:bodyPr
2484        $objWriter->writeElement('a:bodyPr', null);
2485
2486        // a:lstStyle
2487        $objWriter->writeElement('a:lstStyle', null);
2488
2489        // a:p
2490        $objWriter->startElement('a:p');
2491
2492        // a:pPr
2493        $objWriter->startElement('a:pPr');
2494
2495        // a:defRPr
2496        $objWriter->startElement('a:defRPr');
2497        $objWriter->writeAttribute('b', ($oAxis->getTickLabelFont()->isBold() ? 'true' : 'false'));
2498        $objWriter->writeAttribute('i', ($oAxis->getTickLabelFont()->isItalic() ? 'true' : 'false'));
2499        $objWriter->writeAttribute('strike', ($oAxis->getTickLabelFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2500        $objWriter->writeAttribute('sz', ($oAxis->getTickLabelFont()->getSize() * 100));
2501        $objWriter->writeAttribute('u', $oAxis->getTickLabelFont()->getUnderline());
2502        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSuperScript(), 'baseline', '300000');
2503        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSubScript(), 'baseline', '-250000');
2504
2505        // Font - a:solidFill
2506        $objWriter->startElement('a:solidFill');
2507        $this->writeColor($objWriter, $oAxis->getTickLabelFont()->getColor());
2508        $objWriter->endElement();
2509
2510        // Font - a:latin
2511        $objWriter->startElement('a:latin');
2512        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2513        $objWriter->endElement();
2514
2515        // Font - a:ea
2516        $objWriter->startElement('a:ea');
2517        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2518        $objWriter->endElement();
2519
2520        //## a:defRPr
2521        $objWriter->endElement();
2522
2523        //## a:pPr
2524        $objWriter->endElement();
2525
2526        // a:endParaRPr
2527        $objWriter->startElement('a:endParaRPr');
2528        $objWriter->writeAttribute('lang', 'en-US');
2529        $objWriter->writeAttribute('dirty', '0');
2530        $objWriter->endElement();
2531
2532        // ## a:p
2533        $objWriter->endElement();
2534
2535        // ## c:txPr
2536        $objWriter->endElement();
2537
2538        // c:crossAx
2539        $objWriter->startElement('c:crossAx');
2540        $objWriter->writeAttribute('val', $crossAxVal);
2541        $objWriter->endElement();
2542
2543        // c:crosses "autoZero" | "min" | "max" | custom string value
2544        if (in_array($crossesAt, ['autoZero', 'min', 'max'])) {
2545            $objWriter->startElement('c:crosses');
2546            $objWriter->writeAttribute('val', $crossesAt);
2547            $objWriter->endElement();
2548        } else {
2549            $objWriter->startElement('c:crossesAt');
2550            $objWriter->writeAttribute('val', $crossesAt);
2551            $objWriter->endElement();
2552        }
2553
2554        if (Chart\Axis::AXIS_X == $typeAxis) {
2555            // c:lblAlgn
2556            $objWriter->startElement('c:lblAlgn');
2557            $objWriter->writeAttribute('val', 'ctr');
2558            $objWriter->endElement();
2559
2560            // c:lblOffset
2561            $objWriter->startElement('c:lblOffset');
2562            $objWriter->writeAttribute('val', '100');
2563            $objWriter->endElement();
2564
2565            // c:majorUnit
2566            if ($oAxis->getMajorUnit() !== null) {
2567                $objWriter->startElement('c:tickLblSkip');
2568                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2569                $objWriter->endElement();
2570            }
2571        }
2572
2573        if (Chart\Axis::AXIS_Y == $typeAxis) {
2574            // c:crossBetween
2575            $objWriter->startElement('c:crossBetween');
2576            // midCat : Position Axis On Tick Marks
2577            // between : Between Tick Marks
2578            if ($typeChart instanceof Area) {
2579                $objWriter->writeAttribute('val', 'midCat');
2580            } else {
2581                $objWriter->writeAttribute('val', 'between');
2582            }
2583            $objWriter->endElement();
2584
2585            // c:majorUnit
2586            if ($oAxis->getMajorUnit() !== null) {
2587                $objWriter->startElement('c:majorUnit');
2588                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2589                $objWriter->endElement();
2590            }
2591
2592            // c:minorUnit
2593            if ($oAxis->getMinorUnit() !== null) {
2594                $objWriter->startElement('c:minorUnit');
2595                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2596                $objWriter->endElement();
2597            }
2598        }
2599
2600        $objWriter->endElement();
2601    }
2602
2603    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2604    {
2605        // c:spPr
2606        $objWriter->startElement('c:spPr');
2607
2608        // Outline
2609        $this->writeOutline($objWriter, $oGridlines->getOutline());
2610
2611        // ##c:spPr
2612        $objWriter->endElement();
2613    }
2614}